package pl.edu.agh.gt.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Paint;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.List;

import javax.swing.JFrame;

import org.apache.log4j.Logger;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickUnit;
import org.jfree.chart.axis.DateTickUnitType;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.chart.renderer.xy.XYDotRenderer;
import org.jfree.data.statistics.HistogramDataset;
import org.jfree.data.statistics.HistogramType;
import org.jfree.data.time.Hour;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.DefaultXYDataset;

import pl.edu.agh.gt.data.Rate;
import pl.edu.agh.gt.data.RatesHistory;
import pl.edu.agh.gt.data.TradingHistory;
import pl.edu.agh.gt.ga.Individual;
import pl.edu.agh.gt.stock.Trader;

public class ChartDisplay {

	private final static Logger log = Logger.getLogger(ChartDisplay.class);

	public static void tradingChart(String title, RatesHistory hist, TradingHistory trader1, TradingHistory trader2)
			throws IOException {

		try {
			TimeSeriesCollection firstDataset = new TimeSeriesCollection();
			TimeSeriesCollection secondDataset = new TimeSeriesCollection();

			TimeSeries close = new TimeSeries("Close price");
			TimeSeries open = new TimeSeries("Open price");

			// TimeSeries quote = new TimeSeries("Quote amnt");
			// TimeSeries base = new TimeSeries("Base amnt");
			TimeSeries worth1 = new TimeSeries("Trader 1 total");
			TimeSeries worth2 = new TimeSeries("Trader 2 total");

			int i = 0;

			for (Rate r : hist.asSortedList()) {

				Hour hour = new Hour(r.getTime());
				close.add(hour, r.getClose());
				open.add(hour, r.getOpen());

				// quote.add(hour, trades.quoteCurrencyAmnt.get(i));
				// base.add(hour, trades.baseCurrencyAmnt.get(i));
				worth1.add(hour, trader1.totalWorthAmnt.get(i) - Trader.INITIAL_VALUE);
				worth2.add(hour, trader2.totalWorthAmnt.get(i) - Trader.INITIAL_VALUE);

				i++;
			}

			// dataset.addSeries(open);
			firstDataset.addSeries(close);
			// dataset.addSeries(quote);
			// dataset.addSeries(base);
			secondDataset.addSeries(worth1);
			secondDataset.addSeries(worth2);

			JFreeChart chart = ChartFactory.createTimeSeriesChart(title, "time", "eur/dol", firstDataset, true, true,
					false);

			XYPlot plot = chart.getXYPlot();
			plot.setDomainCrosshairVisible(true);
			plot.setRangeCrosshairVisible(true);

			DateAxis xAxis = new DateAxis("Date");
			xAxis.setDateFormatOverride(new SimpleDateFormat("HH:mm dd-MM"));
			xAxis.setTickUnit(new DateTickUnit(DateTickUnitType.HOUR, 10));
			xAxis.setVerticalTickLabels(true);
			plot.setDomainAxis(xAxis);

			StandardXYItemRenderer renderer = new StandardXYItemRenderer();
			NumberAxis axis2 = new NumberAxis();
			// axis2.setAutoRangeIncludesZero(false);
			plot.setDataset(1, secondDataset);
			plot.setRenderer(1, renderer);
			plot.setRangeAxis(1, axis2);
			plot.mapDatasetToRangeAxis(1, 1);

			ChartUtilities.saveChartAsPNG(new File("charts/" + title + ".png"), chart, 1024, 768);

			showJFrame(chart);
		} catch (Exception e) {
			log.error("Error creating chart", e);
		}
	}

	public static void fitnessHistogram(String title, List<Individual> inds) throws IOException {
		try {
			double[] values = new double[inds.size()];
			int i = 0;
			for (Individual ind : inds) {
				values[i] = ind.fitness;
				i++;
			}

			HistogramDataset dataset = new HistogramDataset();
			dataset.setType(HistogramType.RELATIVE_FREQUENCY);
			dataset.addSeries(title, values, 100);
			JFreeChart chart = ChartFactory.createHistogram(title, "", "", dataset, PlotOrientation.VERTICAL, false,
					true, false);

			ChartUtilities.saveChartAsPNG(new File("charts/" + title + ".png"), chart, 800, 600);

			showJFrame(chart);
		} catch (Exception e) {
			log.error("Error creating chart", e);
		}
	}

	public static void genotypeSpaceCoverage(String title, List<Individual> inds, String gen1, String gen2)
			throws IOException {
		try {
			DefaultXYDataset dataset = new DefaultXYDataset();
			final double[][] data = new double[2][inds.size()];
			final double[] fitness = new double[inds.size()];
			double maxFitness = 0;
			double minFitness = Double.MAX_VALUE;
			int i = 0;
			for (Individual ind : inds) {
				data[0][i] = (Float) ind.genotype.getGene(gen1);
				data[1][i] = (Float) ind.genotype.getGene(gen2);
				fitness[i] = ind.fitness;
				if (ind.fitness > maxFitness)
					maxFitness = ind.fitness;
				if (ind.fitness < minFitness)
					minFitness = ind.fitness;
				i++;
			}
			dataset.addSeries(0, data);
			final double max = maxFitness;
			final double min = minFitness;

			NumberAxis xAxis = new NumberAxis(gen1);
			NumberAxis yAxis = new NumberAxis(gen2);
			xAxis.setAutoRangeIncludesZero(false);
			xAxis.setAutoRange(true);
			yAxis.setAutoRangeIncludesZero(false);
			yAxis.setAutoRange(true);
			XYDotRenderer renderer = new XYDotRenderer() {

				@Override
				public Paint getItemPaint(int row, int col) {
					double f = (fitness[col] - min) / (max - min);
					return Color.getHSBColor((float) (0.6 + f * f * 0.4), (float) 1, (float) (0.6 + f * 0.4));
				}
			};
			renderer.setDotHeight(2);
			renderer.setDotWidth(2);

			XYPlot mainPlot = new XYPlot(dataset, xAxis, yAxis, renderer);

			JFreeChart chart = new JFreeChart(null, null, mainPlot, false);
			chart.setTitle(title);

			ChartUtilities.saveChartAsPNG(new File("charts/" + title + ".png"), chart, 800, 600);

			showJFrame(chart);
		} catch (Exception e) {
			log.error("Error creating chart", e);
		}
	}

	public static void genToFitnessRelation(String title, List<Individual> inds, String gen) {
		try {
			DefaultXYDataset dataset = new DefaultXYDataset();
			double[][] data = new double[2][inds.size()];
			int i = 0;
			for (Individual ind : inds) {
				data[0][i] = (Float) ind.genotype.getGene(gen);
				data[1][i] = (Float) ind.fitness;
				i++;
			}
			dataset.addSeries(0, data);

			NumberAxis xAxis = new NumberAxis(gen);
			NumberAxis yAxis = new NumberAxis("Fitness");
			xAxis.setAutoRangeIncludesZero(false);
			xAxis.setAutoRange(true);
			yAxis.setAutoRangeIncludesZero(false);
			yAxis.setAutoRange(true);
			XYDotRenderer renderer = new XYDotRenderer();
			renderer.setDotHeight(2);
			renderer.setDotWidth(2);

			XYPlot mainPlot = new XYPlot(dataset, xAxis, yAxis, renderer);

			JFreeChart chart = new JFreeChart(null, null, mainPlot, false);

			showJFrame(chart);
		} catch (Exception e) {
			log.error("Error creating chart", e);
		}
	}

	private static void showJFrame(JFreeChart chart) {

		ChartPanel chartPanel = new ChartPanel(chart);

		JFrame frame = new JFrame("Chart");
		frame.getContentPane().add(chartPanel, BorderLayout.CENTER);
		frame.pack();
		frame.setVisible(true);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	/**
	 * For testing purposes
	 */
	public static void main(String[] argv) {

		DefaultXYDataset dataset = new DefaultXYDataset();
		final double[][] data = new double[2][100];
		final double[] fitness = new double[100];
		int i = 0;
		for (i = 0; i < 100; i++) {
			data[0][i] = i * 10;
			data[1][i] = i * (-10);
			fitness[i] = i;
		}
		dataset.addSeries(0, data);

		NumberAxis xAxis = new NumberAxis("a");
		NumberAxis yAxis = new NumberAxis("b");
		xAxis.setAutoRangeIncludesZero(false);
		xAxis.setAutoRange(true);
		yAxis.setAutoRangeIncludesZero(false);
		yAxis.setAutoRange(true);
		XYDotRenderer renderer = new XYDotRenderer() {

			@Override
			public Paint getItemPaint(int row, int col) {
				double f = fitness[col] / 100.0;
				return Color.getHSBColor((float) (0.6 + f * f * 0.4), (float) 1, (float) (0.6 + f * 0.4));
			}
		};
		renderer.setDotHeight(5);
		renderer.setDotWidth(5);

		XYPlot mainPlot = new XYPlot(dataset, xAxis, yAxis, renderer);

		JFreeChart chart = new JFreeChart(null, null, mainPlot, false);
		chart.setTitle("");

		showJFrame(chart);
	}

}
